﻿using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using TicTacToe.Core;
using _3DTicTacToe.Net;
using Newtonsoft.Json.Linq;

namespace _3DTicTacToe.UI
{
    partial class NetLobbyWindow : Window
    {
        private readonly bool _host;
        private readonly Connection _connection;
        private readonly Introduction _introduction;

        private readonly Player _localPlayer;
        private Player _remotePlayer;

        private bool _starting;

        public NetLobbyWindow()
        {
            InitializeComponent();
        }

        // this is called by host
        public NetLobbyWindow(Connection connection, Player localPlayer)
            : this()
        {
            _host = true;
            _connection = connection;
            _localPlayer = localPlayer;

            _introduction = new Introduction(_connection, _localPlayer);

            _introduction.OnIntroductonComplete += IntroductionComplete;
            _connection.OnChatMessageReceived += ChatMessageReceived;
            Closing += NetLobbyWindow_Closing;

            SetHostInfo(_localPlayer);

            _introduction.Introduce();
        }

        // this is called by client
        public NetLobbyWindow(Connection connection, Player localPlayer, Player remotePlayer)
            : this()
        {
            _host = false;
            _connection = connection;
            _localPlayer = localPlayer;
            _remotePlayer = remotePlayer;

            SetClientInfo(_localPlayer);
            SetHostInfo(_remotePlayer);

            // hide start button from client
            Height -= startRow.Height.Value;
            startRow.Height = new GridLength(0);
            startButton.Visibility = Visibility.Hidden;

            _connection.OnGameStarts += ConnectionOnGameStarts;
            _connection.OnChatMessageReceived += ChatMessageReceived;
        }

        void IntroductionComplete(Player remotePlayer)
        {
            // too lazy to create a real method :/
            Action<Player> a = player =>
                                   {
                                       _remotePlayer = remotePlayer;
                                       if (_host)
                                       {
                                           SetClientInfo(_remotePlayer);
                                           startButton.IsEnabled = true;
                                       }
                                       else
                                           SetHostInfo(_remotePlayer);
                                   };
            Dispatcher.Invoke(a, remotePlayer);
        }

        void Start()
        {
            NetGame game;

            if (_host) // make sure host is always player 1
                game = new NetGame(_localPlayer, _remotePlayer, _connection);
            else
                game = new NetGame(_remotePlayer, _localPlayer, _connection);

            new GameWindow(game).Show();

            _starting = true;
            Close();
        }

        void ConnectionOnGameStarts()
        {
            Dispatcher.Invoke(new Action(Start), null);
        }

        void NetLobbyWindow_Closing(object sender, CancelEventArgs e)
        {
            if (_starting) return;

            _connection.Shutdown();
            new StartWindow().Show();
        }

        void ChatMessageReceived(NetMessage message)
        {
            var chatMessage = (string) message.Content["Message"];
            Dispatcher.Invoke(new Action<string, string>(AddChatMessage), _remotePlayer.Name, chatMessage);
        }

        void AddChatMessage(string playerName, string message)
        {
            historyTextBox.Text += playerName + "> " + message + Environment.NewLine;
            historyTextBox.ScrollToEnd();
        }

        void SetClientInfo(Player player)
        {
            clientBorder.Background = player.Color.CreateBrush();
            clientContentControl.Foreground = player.Color.Invert().CreateBrush();
            clientContentControl.Content = player.Name;
        }

        void SetHostInfo(Player player)
        {
            hostBorder.Background = player.Color.CreateBrush();
            hostContentControl.Foreground = player.Color.Invert().CreateBrush();
            hostContentControl.Content = player.Name;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var chatMessage = chatMessageTextBox.Text;
            AddChatMessage(_localPlayer.Name, chatMessage);
            chatMessageTextBox.Text = string.Empty;

            var msg = new NetMessage("chat", new JObject {{"Message", chatMessage}});
            _connection.SendMessage(msg);
        }

        private void startButton_Click(object sender, RoutedEventArgs e)
        {
            startButton.IsEnabled = false;
            startButton.Content = "Starting";

            var msg = new NetMessage("game-starting", new JObject());
            _connection.SendMessage(msg);

            Thread.Sleep(50); // let client receive message
            Start();
        }

        private void chatMessageTextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key != Key.Return) return;
            Button_Click(null, null);
        }
    }
}
